#include "bigblock.h"
#include <iostream>
#include <QDebug>
#include "PartitionElement.h"
#include "Sudoku.h"

using namespace std ;

//Main Constructor
BigBlock::BigBlock( SmallBlock* blocks[] )
{
    x = 32000 ;
    y = 32000 ;
    for( int i=0 ; i<9 ; ++i )
    {
        int xCurr = blocks[i]->getX() ;
        int yCurr = blocks[i]->getY() ;

        x = ( xCurr < x ) ? xCurr : x ;
        y = ( yCurr < y ) ? yCurr : y ;
    }

    for( int i=0 ; i<9 ; ++i )
    {
        int xCurr = blocks[ i ]->getX() ;
        int yCurr = blocks[ i ]->getY() ;

        matrix[ xCurr - x ][ yCurr - y ] = blocks[ i ] ;
    }
}



std::ostream& operator<<( std::ostream& out, BigBlock block)
{    
    for( int i=0 ; i<9 ; ++i )
    {
        for( int j=0 ; j<9 ; ++j )
        {
            out << block.matrix[ i/3 ][ j/3 ]->getElement( i%3, j%3 ) << ' ' ;
            if( 0 != j && 8 != j && 0 == (j+1)%3 )
                out << "| " ;
        }
        out << '\n' ;

        if( (0 != i && 8 != i) && ((i+1)/3 != 0) && ((i+1)%3 == 0) )
            out << "---------------------\n" ;
    }
    return out ;
}

std::ostream& BigBlock::print( std::ostream& out )
{
    for( int i=0 ; i<3 ; ++i )
        for( int j=0 ;j<3 ; ++j )
            getSmallBlock( i, j )->print( out ) ;
    return out ;
}

//-----------------Getters and setters--------------------------------

//Get small block with selected coords
SmallBlock* BigBlock::getSmallBlock( int currX, int currY )
{
    return matrix[ currX ][ currY ] ;
}

//Get element with selected coords
short BigBlock::getElement( int currX, int currY )
{
    return getSmallBlock( currX/3, currY/3 )->getElement( currX%3, currY%3 ) ;
}

//Get Cell pointer
Cell* BigBlock::getCell( int currX, int currY )
{
    return getSmallBlock( currX/3, currY/3 )->getCell( currX%3, currY%3 ) ;
}

//Get X coord of big block
int BigBlock::getX()
{
    return x ;
}

//Get Y coord of big block
int BigBlock::getY()
{
    return y ;
}

//Get number of filled elements
int BigBlock::getBusyElements()
{
    int busyCounter = 0 ;
    for( int i=0 ; i<3 ; ++i )
    {
        for( int j=0 ; j<3 ; ++j )
        {
            busyCounter += matrix[ i ][ j ]->getBusyElements() ;
        }
    }
    return busyCounter ;
}


bool BigBlock::checkRules()
{
    bool allIsGood = true ;
    for( int i=0 ; i<3 && allIsGood ; ++i )
    {
        for( int j=0 ; j<3 && allIsGood; ++j )
        {
            allIsGood = matrix[ i ][ j ]->checkRules() ;
        }
    }

    //Check rows
    for( int row=0 ; row<9 && allIsGood ; ++row )
    {
        bool array[] = {true,   false, false, false,
                                false, false, false,
                                false, false, false} ;
        for( int column=0 ; column<9 ; ++column )
        {
            short index = getCell( row, column )->getValue() ;
            array[ index ] = true ;
        }
        for( int index=1 ; index<10 && allIsGood ; ++index )
            if( false == array[ index ] )
                allIsGood = false ;
    }

    //Check columns
    for( int column=0 ; column<9 && allIsGood ; ++column )
    {
        bool array[] = {true,   false, false, false,
                                false, false, false,
                                false, false, false} ;
        for( int row=0 ; row<9 ; ++row )
        {
            short index = getCell( row, column )->getValue() ;
            array[ index ] = true ;
        }
        for( int index=1 ; index<10 && allIsGood ; ++index )
            if( false == array[ index ] )
                allIsGood = false ;
    }

    return allIsGood ;
}


//-----Functions for resolve sudoku------

//--Make the assumption about all digits in block--
int BigBlock::makeTheAssumption()
{
    int counter = 0 ;
    int delta = findInBlock() ;
//    std::cout << "After findInBlock delta=" << delta
//              << " counter=" << counter <<endl
//              << "size=" << Sudoku::partitionVector.size() << std::endl ;
    counter += delta ;
    delta = findInRow() ;
//    std::cout << "After findInRow delta=" << delta
//              << " counter=" << counter <<endl
//              << "size=" << Sudoku::partitionVector.size() << std::endl ;
    counter += delta ;
    delta = findInColumn() ;
//    std::cout << "After findInColumn delta=" << delta
//              << " counter=" << counter <<endl
//              << "size=" << Sudoku::partitionVector.size() << std::endl ;
    counter +=delta ;
    delta = findStealthTwo() ;
//    std::cout << "After findStealthTwo delta=" << delta
//              << " counter=" << counter <<endl
//              << "size=" << Sudoku::partitionVector.size() << std::endl ;
    counter += delta ;
    //delta = findLockedDigit() ;
    //std::cout << "After findStealthTwo delta=" << delta << std::endl ;
    //counter += delta ;
    delta = findLockedDigit2() ;
//    std::cout << "After findStealthTwo delta=" << delta
//              << " counter=" << counter <<endl
//              << "size=" << Sudoku::partitionVector.size() << std::endl ;
    counter += delta ;

    /*
    print( std::cout ) ;
    std::cout << "BusyElement=" << getBusyElements()  << std::endl
              <<"--------------------------------------" << std:: endl ;
    system ( "pause" ) ;
    */

    return counter ;
}

//Exclude digit which already exist in block 3x3
int BigBlock::findInBlock()
{
    int counter = 0 ;
    for( int row=0 ; row<3 ; ++row )
    {
        for( int column=0 ; column<3 ; ++column)
        {
            SmallBlock* smallBlock = matrix[ row ][ column ] ;
            bool array[] = { true,
                                    false, false, false,
                                    false, false, false,
                                    false, false, false,} ;
            //find all filled digits
            for( int i=0 ; i<3 ; ++i )
            {
                for( int j=0 ; j<3 ; ++j )
                {
                    short val = smallBlock->getElement( i, j ) ;
                    if( 0 != val )
                    {
                        array[ val ] = true ;
                    }
                }
            }

            //Delete digits from assumptions
            for( int i=0 ; i<3 ; ++i )
            {
                for( int j=0 ; j<3 ; ++j )
                {
                    Cell* cell = smallBlock->getCell( i, j ) ;
                    if( 0 == cell->getValue() )
                    {
                        for( int index=1 ; index<10 ; ++index )
                        {
                            if( true == array[ index ] )
                            {
                                counter += cell->delAssum( index ) ;
                            }
                        }
                    }
                }
            }
        }
    }
    return counter ;
}

//Exclude digit which already exist in row
int BigBlock::findInRow()
{
    int counter = 0 ;
    for( int row=0 ; row<9 ; ++row )
    {
        bool array[] = { true,
                                false, false, false,
                                false, false, false,
                                false, false, false,} ;
        //Find digits in row
        for( int column=0 ; column<9 ; ++column)
        {
            short val = getElement( row, column ) ;
            if( 0 != val )
            {
                array[ val ] = true ;
            }

        }

        for( int column=0 ; column<9 ; ++column )
        {
            SmallBlock* smallBlock = getSmallBlock( row/3, column/3 ) ;
            Cell* cell = smallBlock->getCell( row%3, column%3 ) ;
            if( 0 == cell->getValue() )
            {
                for( int index=1 ; index<10 ; ++index )
                    if( true == array[ index ] )
                    {
                        counter += cell->delAssum( index ) ;
                    }
            }

        }
    }
    return counter ;
}

//Exclude digit which already exist in column
int BigBlock::findInColumn()
{
    int counter = 0 ;
    for( int column=0 ; column<9 ; ++column )
    {
        bool array[] = { true,
                                false, false, false,
                                false, false, false,
                                false, false, false,} ;
        //Find digits in column
        for( int row=0 ; row<9 ; ++row)
        {
            short val = getElement( row, column ) ;
            if( 0 != val )
            {
                array[ val ] = true ;
            }

        }


        for( int row=0 ; row<9 ; ++row )
        {
            SmallBlock* smallBlock = getSmallBlock( row/3, column/3 ) ;
            Cell* cell = smallBlock->getCell( row%3, column%3 ) ;
            if( 0 == cell->getValue() )
            {
                for( int index=1 ; index<10 ; ++index )
                    if( true == array[ index ] )
                    {
                        counter += cell->delAssum( index ) ;
                    }
            }

        }
    }
    return counter ;
}

//If exist two equals couple exclude this digit from other cells
//If exist in row, exclude from row etc.
int BigBlock::findStealthTwo()
{
    int counterAssum = 0 ;
    //find in blocks 3x3
    for( int row=0 ; row<3 ; ++row )
    {
        for( int column=0 ; column<3 ; ++column )
        {
            SmallBlock* smallBlock = getSmallBlock( row, column ) ;
            for( int i=0 ; i<3 ; ++i )
            {
                for( int j=0 ; j<3 ; ++j )
                {
                    Cell* cell = smallBlock->getCell( i, j ) ;
                    Assumption assum = cell->getAssumption() ;
                    if( 0 != cell->getValue() || 2 != assum.count() )
                        continue ;
                    for( int innerI=i ; innerI<3 ; ++innerI )
                    {
                        for( int innerJ=j ; innerJ<3 ; ++innerJ )
                        {
                            Cell* innerCell = smallBlock->getCell( innerI, innerJ ) ;
                            if( cell == innerCell )
                                continue ;
                            Assumption innerAssum = innerCell->getAssumption() ;
                            if( assum == innerAssum )
                            {
                               short dig1 = -1 ;
                               short dig2 = -1 ;
                               for( int index=1 ; index<10 ; ++index )
                               {
                                   if( Can == assum.getAssum( index ) )
                                   {
                                       if( -1 == dig1 )
                                           dig1 = index ;
                                       else
                                           dig2 = index ;
                                   }
                               }

                               //std::cout << "Finded StealthTwo["    //---
                               //          << smallBlock->getX()      //---
                               //          << "][" << smallBlock->getY() << "]" << std::endl  //---
                               //          << *cell << std::endl      //---
                               //          << *innerCell << std::endl //---
                               //          << "dig1=" << dig1 << std::endl << "dig2=" << dig2 << std::endl    //---
                               //          << *smallBlock ;   //---
                               //smallBlock->print( std::cout ) ; //---

                               for( int row=0 ; row<3 ; ++row )
                               {
                                   for( int column=0 ; column<3 ; ++column )
                                   {
                                       Cell* currCell = smallBlock->getCell( row, column ) ;
                                       if( currCell == cell || currCell == innerCell || 0 != currCell->getValue() )
                                           continue ;
                                        counterAssum += currCell->delAssum( dig1 ) ;
                                        counterAssum += currCell->delAssum( dig2 ) ;
                                   }
                               }

                            }
                        }
                    }
                }
            }
        }
    }

    //find in row
    for( int row=0 ; row<9 ; ++row )
    {
        for( int column=0 ; column<9 ; ++column )
        {
            SmallBlock* smallBlock = getSmallBlock( row/3, column/3 ) ;
            Cell* cell = smallBlock->getCell( row%3, column/3 ) ;
            Assumption assum = cell->getAssumption() ;
            if( 0 != cell->getValue() || 2 != assum.count() )
                continue ;
            for( int innerColumn=column+1 ; innerColumn<9 ; ++innerColumn )
            {
                Cell* innerCell = getSmallBlock( row/3, innerColumn/3 )->getCell( row%3, innerColumn%3 ) ;
                if( cell == innerCell || 0 != innerCell->getValue() )
                    continue ;
                Assumption innerAssum = innerCell->getAssumption() ;
                if( assum == innerAssum )
                {
                    short dig1 = -1 ;
                    short dig2 = -1 ;
                    for( int index=1 ; index<10 ; ++index )
                    {
                        if( Can == assum.getAssum( index ) )
                        {
                            if( -1 == dig1 )
                                dig1 = index ;
                            else
                                dig2 = index ;
                        }
                    }

                    for( int index=0 ; index<9 ; ++index )
                    {
                        Cell* currCell = getSmallBlock( row/3, index/3 )->getCell( row%3, index%3 ) ;
                        if( currCell == cell || currCell == innerCell || 0 != currCell->getValue() )
                            continue ;
                        counterAssum += currCell->delAssum( dig1 ) ;
                        counterAssum += currCell->delAssum( dig2 ) ;
                    }



                }
            }
        }

    }

    //Find in column
    for( int column=0 ; column<9 ; ++column )
    {
        for( int row=0 ; row<9 ; ++row )
        {
            SmallBlock* smallBlock = getSmallBlock( row/3, column/3 ) ;
            Cell* cell = smallBlock->getCell( row%3, column%3 ) ;
            Assumption assum = cell->getAssumption() ;
            if( 0 != cell->getValue() || 2 != assum.count() )
                continue ;
            for( int innerRow=row+1 ; innerRow<9 ; ++innerRow )
            {
                Cell* innerCell = getSmallBlock( innerRow/3, column/3 )->getCell( innerRow%3, column%3 ) ;
                if( 0 != innerCell->getValue() )
                    continue ;
                Assumption innerAssum = innerCell->getAssumption() ;
                if( assum == innerAssum )
                {
                    short dig1 = -1 ;
                    short dig2 = -1 ;
                    for( int index=1 ; index<10 ; ++index )
                    {
                        if( Can == assum.getAssum( index ) )
                        {
                            if( -1 == dig1 )
                                dig1 = index ;
                            else
                                dig2 = index ;
                        }
                    }

                    for( int index=0 ; index<9 ; ++index )
                    {
                        Cell* currCell = getSmallBlock( index/3, column/3 )->getCell( index%3, column%3 ) ;
                        if( currCell == cell || currCell == innerCell || 0 != currCell->getValue() )
                            continue ;
                        counterAssum += currCell->delAssum( dig1 ) ;
                        counterAssum += currCell->delAssum( dig2 ) ;
                    }

                }
            }
        }

    }

    return counterAssum ;
}

int BigBlock::findLockedDigit()
{
    int counterAssumption = 0 ;


    for( int row=0 ; row<3 ; ++ row )
    {
        for( int column=0 ; column<3 ; ++column )
        {
            SmallBlock* smallBlock = getSmallBlock( row, column ) ;
            CanBeInCell array[] = {NotCan,  Can, Can, Can,
                                            Can, Can, Can,
                                            Can, Can, Can} ;
            //Найти все непоставленные элементы
            for( int i=0 ; i<3 ; ++i )
            {
                for( int j=0 ; j<3 ; ++j )
                {
                    short val = smallBlock->getElement( i, j ) ;
                    array[ val ] = NotCan ;
                }
            }

            //Проверить каждый непровереный элемент
            for( short currDigit=1 ; currDigit<10 ; ++currDigit )
            {
                if( Can != currDigit )
                    continue ;


                //По строкам
                bool rowLuck = true ;
                bool rowIsBusy = false ;
                short busyRowNumber = -1 ;

                for( int i=0 ; i<3 && rowLuck; ++i )
                {
                    for( int j=0 ; j<3 && rowLuck ; ++j )
                    {
                        Cell* cell = smallBlock->getCell( i, j ) ;
                        if( 0 != cell->getValue() )
                            continue ;
                        if( Can == cell->getAssumption().getAssum( currDigit ) )
                        {
                            if( false == rowIsBusy )
                            {
                                rowIsBusy = true ;
                                busyRowNumber = i ;

                            }
                            else
                            {
                                if( i != busyRowNumber )
                                {
                                    rowLuck = false ;
                                }
                            }
                        }
                    }
                }

                if( true == rowLuck )
                {
                    std::cout << "Finded locked element " << currDigit << std::endl << *smallBlock ;    //--
                    //smallBlock->print( std::cout ) ;                    //--
                    for( int i=0 ; i<9 ; ++i )  //--
                    {                           //--
                        Cell* cell = smallBlock->getCell( busyRowNumber, i ) ;    //--
                        std::cout << *cell << std::endl ;       //--
                    }                           //--

                    for( int innerColumn=0 ; innerColumn<3 && innerColumn != column ; ++innerColumn )
                    {
                        SmallBlock* block = getSmallBlock( row, innerColumn ) ;
                        for( int i=0 ; i<3 ; ++i )
                        {
                            Cell* cell = block->getCell( busyRowNumber, i ) ;
                            if( 0 == cell->getValue() )
                            {
                                counterAssumption += cell->delAssum( currDigit ) ;
                            }
                        }
                    }

                }


                //По столбцам
                bool columnLuck = true ;
                bool columnIsBusy = false ;
                short busyColumn = -1 ;
                for( int i=0 ; i<3 && columnLuck ; ++i )
                {
                    for( int j=0 ; j<3 && columnLuck ; ++j )
                    {
                        Cell* cell = smallBlock->getCell( i, j ) ;
                        if( 0 != cell->getValue() )
                            continue ;
                        if( Can == cell->getAssumption().getAssum( currDigit ) )
                        {
                            if( false == columnIsBusy )
                            {
                                columnIsBusy = true ;
                                busyColumn = j ;
                            }
                            else
                            {
                                if( busyColumn != j)
                                {
                                    columnLuck = false ;
                                }
                            }
                        }
                    }
                }

                if( true == columnLuck )
                {
                    for( int i=0 ; i<3 && i != row ; ++i )
                    {
                        SmallBlock* block = getSmallBlock( i, column ) ;
                        for( int index=0 ; index<3 ; ++index )
                        {
                            Cell* cell = block->getCell( index, busyColumn ) ;
                            if( 0 != cell->getValue() )
                                continue ;
                            counterAssumption += cell->delAssum( currDigit ) ;
                        }
                    }
                }

            }
        }
    }
    return counterAssumption ;
}

int BigBlock::findLockedDigit2()
{
    int counterAssumption = 0 ;

    for( int row=0 ; row<9 ; ++row )
    {

        CanBeInCell array[] = {NotCan,  Can, Can, Can,
                                        Can, Can, Can,
                                        Can, Can, Can} ;
        //Find all exists elements in row and mark in arra[] as NotCane
        for( int column=0 ; column<9 ; ++column )
        {
            short val = getElement( row, column ) ;
            array[ val ] = NotCan ;
        }

        //Find small block which single contains digit in assumption
        for( int currDigit=1 ; currDigit<10 ; ++currDigit )
        {
            if( NotCan == array[ currDigit ] )
                continue ;
            bool luck = true ;
            bool blockSelected = false ;
            short selectedBlock = -1 ;

            for( int column=0 ; column<9 && luck ; ++column )
            {
                Cell* cell = getCell( row, column ) ;
                if( 0 != cell->getValue() )
                    continue ;
                if( Can == cell->getAssumption().getAssum( currDigit ) )
                {
                    if( blockSelected )
                    {
                        if( column/3 == selectedBlock )
                            continue ;
                        else
                            luck = false ;
                    }
                    else
                    {
                        blockSelected = true ;
                        selectedBlock = column/3 ;
                    }
                }
            }

            //If finded
            if( luck && blockSelected )
            {
                SmallBlock* smallBLock = getSmallBlock( row/3, selectedBlock ) ;
                for( int i=0 ; i<3 && i!=row%3 ; ++i )
                {
                    for( int j=0 ; j<3 ; ++j )
                    {
                        Cell* cell = smallBLock->getCell( i, j ) ;
                        if( 0 != cell->getValue() )
                            continue ;
                        counterAssumption += cell->delAssum( currDigit ) ;
                    }
                }
            }
        }

    }


    for( int column=0 ; column<9 ; ++column )
    {
        CanBeInCell array[] = {NotCan,  Can, Can, Can,
                                        Can, Can, Can,
                                        Can, Can, Can} ;
        //Find all exists elements in row and mark in arra[] as NotCane
        for( int row=0 ; row<9 ; ++row)
        {
            short val = getElement( row, column ) ;
            array[ val ] = NotCan ;
        }

        //Find small block which single contains digit in assumption
        for( int currDigit=1 ; currDigit<10 ; ++currDigit )
        {
            if( NotCan == array[ currDigit ] )
                continue ;
            bool luck = true ;
            bool blockSelected = false ;
            short selectedBlock = -1 ;

            for( int row=0 ; row<9 && luck ; ++row)
            {
                Cell* cell = getCell( row, column ) ;
                if( 0 != cell->getValue() )
                    continue ;
                if( Can == cell->getAssumption().getAssum( currDigit ) )
                {
                    if( blockSelected )
                    {
                        if( row/3 == selectedBlock )
                            continue ;
                        else
                            luck = false ;
                    }
                    else
                    {
                        blockSelected = true ;
                        selectedBlock = row/3 ;
                    }
                }
            }

            //If finded
            if( luck && blockSelected )
            {
                SmallBlock* smallBLock = getSmallBlock( selectedBlock, column/3 ) ;
                for( int i=0 ; i<3  ; ++i )
                {
                    for( int j=0 ; j<3 && j!=column%3 ; ++j )
                    {
                        Cell* cell = smallBLock->getCell( i, j ) ;
                        if( 0 != cell->getValue() )
                            continue ;
                        counterAssumption += cell->delAssum( currDigit ) ;
                    }
                }
            }
        }
    }

    return counterAssumption ;
}


int BigBlock::findXWing()
{
    int assumptionCounter = 0 ;
    int array[9][10] = { {0,  0, 0, 0, 0, 0, 0, 0, 0, 0} ,
                      {0,  0, 0, 0, 0, 0, 0, 0, 0, 0} ,
                      {0,  0, 0, 0, 0, 0, 0, 0, 0, 0} ,
                      {0,  0, 0, 0, 0, 0, 0, 0, 0, 0} ,
                      {0,  0, 0, 0, 0, 0, 0, 0, 0, 0} ,
                      {0,  0, 0, 0, 0, 0, 0, 0, 0, 0} ,
                      {0,  0, 0, 0, 0, 0, 0, 0, 0, 0} ,
                      {0,  0, 0, 0, 0, 0, 0, 0, 0, 0} ,
                      {0,  0, 0, 0, 0, 0, 0, 0, 0, 0}
                    } ;

    for( int row=0 ; row<9 ; ++row )
    {
        for( int column=0 ; column<9 ; ++column )
        {
            Cell* cell = getCell( row, column ) ;
            if( 0 != cell->getValue() )
                continue ;
            Assumption assum = cell->getAssumption() ;
            for( int i=1 ; i<10 ; ++i )
            {
                if( Can == assum.getAssum( i ) )
                    ++array[row][ i ] ;
            }
        }
    }

    //Ищем двойки в каждой строке
    for( int row=0 ; row<9 ; ++row )
    {
        //Вроверяем на двойку все элементы
        for( int index=1 ; index<10 ; ++index )
        {
            //Мы нашли двойку
            if( 2 != array[ row ][ index ] )
                continue ;

            //Пытаемся найти вторую строку с двойкой для такого же предположения
            for( int rowSecondEl=row+1 ; rowSecondEl<9 ; ++rowSecondEl )
            {
                //Мы нашли вторую двойку
                if( 2 != array[ rowSecondEl][ index ] )
                    continue ;

                int columnNumberOne = -1 ;
                int columnNumberTwo = -1 ;
                //Ищем колонки для этих двоек
                for( int column=0 ; column<9 ; ++column )
                {
                    Cell* cell = getCell( row, column ) ;
                    if( 0 != cell->getValue() )
                        continue ;
                    //Мы нашли двойку (это первая или вторая)
                    if( Can == cell->getAssumption().getAssum( index ) )
                    {
                        if( -1 == columnNumberOne )
                        {
                            columnNumberOne = column ;
                        }
                        else
                        {
                            columnNumberTwo = column ;
                            break ;
                        }
                    }
                }
                //Проверяем подходяти ли по этим колонкам вторая строка

                Cell* cell1 = getCell( rowSecondEl, columnNumberOne) ;
                Cell* cell2 = getCell( rowSecondEl, columnNumberTwo) ;
                if( -1 != columnNumberOne &&
                        0 == cell1->getValue() && 0 == cell2->getValue() &&
                        Can == cell1->getAssumption().getAssum( index ) &&
                        Can == cell2->getAssumption().getAssum( index ) )
                {
                    /*
                    system( "cls" ) ;
                    for( int i=0 ; i<9 ; ++i )
                    {
                        for( int j=1 ; j<10 ; ++j )
                        {
                            std::cout << array[i][j] << ' ' ;
                        }
                        std::cout << std::endl ;
                    }
                    std::cout << "x=" << getX() << " y=" << getY() << std :: endl ;
                    std::cout << "row=" << row << " rowSecondEl=" << rowSecondEl << std::endl
                              << "columnNumberOne=" << columnNumberOne << " columnNumberTwo=" << columnNumberTwo << std::endl
                              << "index=" << index << std::endl
                                 << *cell1 <<  std::endl
                                 << *cell2 <<std::endl
                                 << *this ;
                    system( "pause" ) ;
                    print( std::cout ) ;
                    system( "pause" ) ;
                    */
                    //Значит подходят, тогда удаляем все другие элементы по периметру

                    //Delete assumption from [row][columnNumberOne] to [row][columnNumberTwo]
                    for( int column=columnNumberOne+1 ; column<columnNumberTwo ; ++column )
                    {
                        Cell* cell = getCell( row, column ) ;
                        if( 0 != cell->getValue() )
                            continue ;
                        assumptionCounter += cell->delAssum( index ) ;
                    }
                    //Delete assumption from [rowSecondEl][columnNumberOne] to [rowSecondEl][columnNumberTwo]
                    for( int column=columnNumberOne+1 ; column<columnNumberTwo ; ++column )
                    {
                        Cell* cell = getCell( rowSecondEl, column ) ;
                        if( 0 != cell->getValue() )
                            continue ;
                        assumptionCounter += cell->delAssum( index ) ;
                    }
                    //Delete assumption from [row][columnNumberOne] to [rowSecondEl][columnNumberOne]
                    for( int i=row+1 ; i<rowSecondEl ; ++i )
                    {
                        Cell* cell = getCell( i, columnNumberOne ) ;
                        if( 0 != cell->getValue() )
                            continue ;
                        assumptionCounter += cell->delAssum( index ) ;
                    }
                    //Delete assumption from [row][columnNumberTwo] to [rowSecondEl][columnNumberTwo]
                    for( int i=row+1 ; i<rowSecondEl ; ++i )
                    {
                        Cell* cell = getCell( i, columnNumberTwo ) ;
                        if( 0 != cell->getValue() )
                            continue ;
                        assumptionCounter += cell->delAssum( index ) ;
                    }
                }

            }
        }
    }

   /*
    //Clear array
    for( int i=0 ; i<9 ; ++i )
    {
        for( int j=1 ; j<10 ; ++j )
        {
            array[ i ][ j ] = 0 ;
        }
    }
    //Find in row
    for( int column=0 ; column<9 ; ++column )
    {
        for( int row=0 ; row<9 ; ++row )
        {
            Cell* cell = getCell( row, column ) ;
            if( 0 != cell->getValue() )
                continue ;
            Assumption* assum = cell->getAssumption() ;
            for( int i=1 ; i<10 ; ++i )
            {
                if( Can == assum->getAssum( i ) )
                    ++array[column][ i ] ;
            }
        }
    }
    */
    return assumptionCounter ;
}



//--Get partition element base on assumption--
PartitionElement* BigBlock::getPartitionElement()
{
    PartitionElement* partition = 0 ;

    partition = findSingles() ;
    if( 0 != partition )
    {
        //std::cout << "findSingles() find" << std::endl ;
        return partition ;
    }


    partition = findStealthSingles() ;
    if( 0 != partition )
    {
        //std::cout << "findStealthSingles() find" << std::endl ;
        return partition ;
    }


    return 0 ;
}

//If in assumption only one digit, set is as value
PartitionElement* BigBlock::findSingles()
{
    for( int row=0 ; row<9 ; ++row )
    {
        for( int column=0 ; column<9 ; ++column )
        {
            SmallBlock* smallBlock = getSmallBlock( row/3, column/3 ) ;
            Cell* cell = smallBlock->getCell( row%3, column%3 ) ;
            if( 1 == cell->count() && 0 == cell->getValue() )
            {
                Assumption assum = cell->getAssumption() ;
                short newValue = assum.getExclusive() ;
                return new PartitionElement( cell, newValue ) ;
            }
        }
    }
    return 0 ;
}

//If digit exist in only one assumption, set it as value
PartitionElement* BigBlock::findStealthSingles()
{
    int digits[] = {0,  0, 0, 0,
                        0, 0, 0,
                        0, 0, 0} ;

    //Find in block 3x3
    for( int blockRow=0 ; blockRow<3 ; ++blockRow )
    {
        for( int blockColumn=0 ; blockColumn<3 ; ++blockColumn )
        {
            digits[1] = 0 ;
            digits[2] = 0 ;
            digits[3] = 0 ;
            digits[4] = 0 ;
            digits[5] = 0 ;
            digits[6] = 0 ;
            digits[7] = 0 ;
            digits[8] = 0 ;
            digits[9] = 0 ;
            SmallBlock* smallBlock = matrix[ blockRow ][ blockColumn ] ;
            for( int i=0 ; i<3 ; ++i )
            {
                for( int j=0 ; j<3 ; ++j )
                {
                    Cell* cell = smallBlock->getCell( i, j ) ;
                    if( 0 != cell->getValue() )
                        continue ;
                    Assumption assum = cell->getAssumption() ;
                    for( int index=1 ; index<10 ; ++index )
                    {
                        if( Can == assum.getAssum( index ) )
                            ++digits[ index ] ;
                    }
                }
            }
            for( int currDigit=1 ; currDigit<10 ; ++currDigit )
            {
                if( 1 == digits[ currDigit ] )
                {

                    for( int i=0 ; i<3 ; ++i )
                    {
                        for( int j=0 ; j<3 ; ++j )
                        {
                            Cell* cell = smallBlock->getCell( i, j ) ;
                            if( 0 != cell->getValue() )
                                continue ;
                            Assumption assum = cell->getAssumption() ;
                            if( Can == assum.getAssum( currDigit ) )
                                return new PartitionElement( cell, currDigit ) ;
                        }
                    }
                }
            }
        }
    }

    //Find in row
    for( int row=0 ; row<9 ; ++row )
    {
        digits[1] = 0 ;
        digits[2] = 0 ;
        digits[3] = 0 ;
        digits[4] = 0 ;
        digits[5] = 0 ;
        digits[6] = 0 ;
        digits[7] = 0 ;
        digits[8] = 0 ;
        digits[9] = 0 ;
        for( int column ; column<9 ; ++column )
        {
               SmallBlock* smallBlock = matrix[ row/3 ][ column/3 ] ;
               Cell* cell = smallBlock->getCell( row%3, column%3 ) ;
               if( 0 != cell->getValue() )
                   continue ;
               Assumption assum = cell->getAssumption() ;
               for( int i=1 ; i<10 ; ++i )
               {
                   if( Can == assum.getAssum( i ) )
                       ++digits[ i ] ;
               }
        }

        for( int currDigit=1 ; currDigit<10 ; ++currDigit )
        {
            if( 1 == digits[ currDigit ] )
            {
                for( int column ; column<9 ; ++column )
                {
                       SmallBlock* smallBlock = matrix[ row/3 ][ column/3 ] ;
                       Cell* cell = smallBlock->getCell( row%3, column%3 ) ;
                       if( 0 != cell->getValue() )
                           continue ;
                       Assumption assum = cell->getAssumption() ;
                       if( Can == assum.getAssum( currDigit ) )
                       {
                           return new PartitionElement( cell, currDigit ) ;
                       }
                }
            }
        }
    }

    //Find in columns
    for( int column=0 ; column<9 ; ++column )
    {
        digits[1] = 0 ;
        digits[2] = 0 ;
        digits[3] = 0 ;
        digits[4] = 0 ;
        digits[5] = 0 ;
        digits[6] = 0 ;
        digits[7] = 0 ;
        digits[8] = 0 ;
        digits[9] = 0 ;
        for( int row ; row<9 ; ++row)
        {
               SmallBlock* smallBlock = matrix[ row/3 ][ column/3 ] ;
               Cell* cell = smallBlock->getCell( row%3, column%3 ) ;
               if( 0 != cell->getValue() )
                   continue ;
               Assumption assum = cell->getAssumption() ;
               for( int i=1 ; i<10 ; ++i )
               {
                   if( Can == assum.getAssum( i ) )
                       ++digits[ i ] ;
               }
        }

        for( int currDigit=1 ; currDigit<10 ; ++currDigit )
        {
            if( 1 == digits[ currDigit ] )
            {
                for( int row ; row<9 ; ++row )
                {
                       SmallBlock* smallBlock = matrix[ row/3 ][ column/3 ] ;
                       Cell* cell = smallBlock->getCell( row%3, column%3 ) ;
                       if( 0 != cell->getValue() )
                           continue ;
                       Assumption assum = cell->getAssumption() ;
                       if( Can == assum.getAssum( currDigit ) )
                       {
                           return new PartitionElement( cell, currDigit ) ;
                       }
                }
            }
        }
    }
    return 0 ;
}


/*
PartitionElement* BigBlock::findStealthThree()
{return 0 ;}
//int BigBlock::findStealthFour() ;
PartitionElement* BigBlock::findBareTwo()
{return 0 ;}
PartitionElement* BigBlock::findBareThree()
{return 0 ;}
//int findBareFour() ;

PartitionElement* BigBlock::findXWing()
{return 0 ;}
*/

bool BigBlock::allIsFilled()
{
    for( int i=0 ; i<3 ; ++i )
    {
        for( int j=0 ; j<3 ; ++j )
        {
            if( false == matrix[i][j]->allIsFilled() )
                return false ;
        }
    }
    return true ;
}

bool BigBlock::assumptionsIs()
{
    for( int i=0 ; i<3 ; ++i )
    {
        for( int j=0 ; j<3 ; ++j )
        {
            if( true == matrix[i][j]->assumptionsIs() )
                return true ;
        }
    }
    return false ;
}
